# -*- coding: utf-8 -*-
"""
搜索增强服务 - DuckDuckGo集成
"""

import asyncio
import aiohttp
import json
import time
from typing import List, Dict, Optional
from urllib.parse import quote
import logging

logger = logging.getLogger(__name__)

class SearchResult:
    def __init__(self, title: str, url: str, snippet: str):
        self.title = title
        self.url = url
        self.snippet = snippet

class DuckDuckGoSearchService:
    def __init__(self):
        self.timeout = 15.0  # 搜索超时时间（秒）- 增加超时时间
        self.max_results = 5  # 最大搜索结果数
        self.token_limit = 500  # 搜索结果token限制
        
    async def search(self, query: str) -> List[SearchResult]:
        """
        执行多源搜索策略
        
        Args:
            query: 搜索查询
            
        Returns:
            List[SearchResult]: 搜索结果列表
        """
        start_time = time.time()
        
        # 尝试多种搜索方法
        search_methods = [
            self._search_duckduckgo_html,
            self._search_duckduckgo_api,
            self._search_bing_fallback
        ]
        
        for method in search_methods:
            try:
                results = await method(query)
                if results:
                    elapsed_time = time.time() - start_time
                    logger.info(f"搜索成功: 方法={method.__name__}, 查询='{query}', 结果数={len(results)}, 耗时={elapsed_time:.2f}秒")
                    return results[:self.max_results]
            except Exception as e:
                logger.warning(f"搜索方法 {method.__name__} 失败: {str(e)}")
                continue
        
        # 所有方法都失败时返回空结果，让AI知道搜索不可用
        logger.error(f"所有搜索方法都失败: 查询='{query}'")
        return []
    
    async def _search_duckduckgo_html(self, query: str) -> List[SearchResult]:
        """通过DuckDuckGo HTML搜索"""
        encoded_query = quote(query)
        url = f"https://html.duckduckgo.com/html/?q={encoded_query}"
        
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
        }
        
        timeout = aiohttp.ClientTimeout(total=self.timeout)
        
        # 创建SSL上下文，禁用证书验证（仅用于开发测试）
        import ssl
        ssl_context = ssl.create_default_context()
        ssl_context.check_hostname = False
        ssl_context.verify_mode = ssl.CERT_NONE
        
        connector = aiohttp.TCPConnector(ssl=ssl_context)
        
        async with aiohttp.ClientSession(timeout=timeout, headers=headers, connector=connector) as session:
            async with session.get(url) as response:
                if response.status == 200:
                    html_content = await response.text()
                    return self._parse_duckduckgo_html(html_content)
        return []
    
    async def _search_duckduckgo_api(self, query: str) -> List[SearchResult]:
        """使用DuckDuckGo即时答案API"""
        encoded_query = quote(query)
        url = f"https://api.duckduckgo.com/?q={encoded_query}&format=json&no_html=1&skip_disambig=1"
        
        timeout = aiohttp.ClientTimeout(total=self.timeout)
        
        async with aiohttp.ClientSession(timeout=timeout) as session:
            async with session.get(url) as response:
                if response.status == 200:
                    data = await response.json()
                    return self._parse_duckduckgo_results(data)
        return []
    
    async def _search_bing_fallback(self, query: str) -> List[SearchResult]:
        """Bing搜索回退方案"""
        # 注意：这需要Bing Search API密钥，这里是示例结构
        # 实际部署时需要配置API密钥
        logger.info(f"尝试Bing搜索回退: {query}")
        # 暂时返回空结果，避免无API密钥时出错
        return []
    
    def _parse_duckduckgo_results(self, data: Dict) -> List[SearchResult]:
        """
        解析DuckDuckGo API返回的数据
        
        Args:
            data: API返回的JSON数据
            
        Returns:
            List[SearchResult]: 解析后的搜索结果
        """
        results = []
        
        try:
            # 处理即时答案
            if data.get('Abstract'):
                results.append(SearchResult(
                    title="即时答案",
                    url=data.get('AbstractURL', ''),
                    snippet=data.get('Abstract', '')
                ))
            
            # 处理相关主题
            for topic in data.get('RelatedTopics', []):
                if isinstance(topic, dict) and topic.get('Text'):
                    results.append(SearchResult(
                        title=topic.get('Text', '')[:100] + '...' if len(topic.get('Text', '')) > 100 else topic.get('Text', ''),
                        url=topic.get('FirstURL', ''),
                        snippet=topic.get('Text', '')
                    ))
            
            # 处理答案
            if data.get('Answer'):
                results.append(SearchResult(
                    title="快速答案",
                    url=data.get('AnswerURL', ''),
                    snippet=data.get('Answer', '')
                ))
                
        except Exception as e:
            logger.error(f"解析搜索结果异常: {str(e)}")
        
        return results
    
    def _parse_duckduckgo_html(self, html_content: str) -> List[SearchResult]:
        """
        解析DuckDuckGo HTML搜索结果
        
        Args:
            html_content: HTML内容
            
        Returns:
            List[SearchResult]: 解析后的搜索结果
        """
        results = []
        
        try:
            # 简单的HTML解析，提取搜索结果
            import re
            
            # 查找搜索结果块 - 更宽泛的模式
            result_patterns = [
                # 尝试匹配标准的搜索结果格式
                r'<h2[^>]*result__title[^>]*>.*?<a[^>]+href="([^"]+)"[^>]*>([^<]+)</a>.*?</h2>.*?<div[^>]*result__snippet[^>]*>([^<]+)</div>',
                # 备用模式
                r'<a[^>]+href="([^"]+)"[^>]*>([^<]+)</a>.*?<p[^>]*>([^<]+)</p>',
                # 简单模式
                r'href="(https?://[^"]+)"[^>]*>([^<]{10,})</a>'
            ]
            
            for pattern in result_patterns:
                matches = re.findall(pattern, html_content, re.DOTALL | re.IGNORECASE)
                
                for match in matches[:self.max_results]:
                    if len(match) >= 2:
                        url = match[0]
                        title = match[1]
                        snippet = match[2] if len(match) > 2 else f"搜索结果来自 {url}"
                        
                        # 清理HTML标签和多余空格
                        title = re.sub(r'<[^>]+>', '', title).strip()
                        snippet = re.sub(r'<[^>]+>', '', snippet).strip()
                        
                        if title and len(title) > 5 and url.startswith('http'):
                            results.append(SearchResult(
                                title=title[:100],  # 限制标题长度
                                url=url,
                                snippet=snippet[:200]  # 限制摘要长度
                            ))
                
                if results:
                    break  # 找到结果就停止尝试其他模式
                        
        except Exception as e:
            logger.error(f"解析HTML搜索结果异常: {str(e)}")
        
        return results
    
    def _get_mock_results(self, query: str) -> List[SearchResult]:
        """
        获取模拟搜索结果用于测试（当真实搜索失败时）
        
        Args:
            query: 搜索查询
            
        Returns:
            List[SearchResult]: 模拟搜索结果列表
        """
        logger.info(f"使用模拟搜索结果: 查询='{query}'")
        
        # 根据查询类型返回不同的模拟结果
        if any(word in query.lower() for word in ['天气', 'weather', '温度', '气温']):
            return [
                SearchResult(
                    title="北京今日天气预报",
                    url="https://weather.cma.gov.cn/beijing",
                    snippet="北京今日天气：晴转多云，温度18-26°C，西北风3级，湿度45%，空气质量优。紫外线指数中等，适合户外活动。建议穿着轻便长袖。"
                ),
                SearchResult(
                    title="中国气象网 - 北京实时天气",
                    url="https://weather.sina.com.cn/beijing",
                    snippet="实时天气：北京当前温度22°C，体感温度24°C，晴间多云，能见度15公里。今日日出时间06:32，日落时间18:45。"
                ),
                SearchResult(
                    title="北京一周天气趋势",
                    url="https://www.weather.com.cn/weather/101010100.shtml",
                    snippet="未来一周北京天气相对稳定，气温在16-28°C之间波动，以晴到多云天气为主，周中有小雨，整体适宜出行。"
                )
            ]
        elif any(word in query.lower() for word in ['时间', 'time', '几点', '现在']):
            import datetime
            now = datetime.datetime.now()
            current_time = now.strftime("%Y年%m月%d日 %H:%M:%S")
            return [
                SearchResult(
                    title="北京时间",
                    url="https://time.is/Beijing",
                    snippet=f"北京时间：{current_time}（UTC+8）。当前为北京标准时间，与协调世界时相差8小时。"
                ),
                SearchResult(
                    title="中国科学院国家授时中心",
                    url="https://www.ntsc.ac.cn",
                    snippet=f"标准北京时间：{current_time}。国家授时中心负责维护和发播中国标准时间，确保时间精度。"
                )
            ]
        elif any(word in query.lower() for word in ['价格', 'price', '多少钱', '成本']):
            return [
                SearchResult(
                    title="2024年最新价格信息",
                    url="https://price.example.com",
                    snippet="根据最新市场数据，相关产品价格有所波动，建议参考官方报价。"
                )
            ]
        elif any(word in query.lower() for word in ['ai', '人工智能', '技术发展', '最新']):
            return [
                SearchResult(
                    title="2024年AI技术发展趋势",
                    url="https://tech.example.com/ai-2024",
                    snippet="2024年AI技术呈现快速发展趋势，大语言模型、多模态AI、边缘计算等领域取得重要突破。"
                ),
                SearchResult(
                    title="人工智能最新研究进展",
                    url="https://research.example.com/ai",
                    snippet="最新研究显示，AI在医疗、教育、自动驾驶等领域应用不断深化，技术成熟度持续提升。"
                )
            ]
        else:
            return [
                SearchResult(
                    title="相关信息",
                    url="https://search.example.com",
                    snippet=f"关于'{query}'的相关信息。由于网络搜索暂时不可用，这是模拟的搜索结果用于演示。"
                )
            ]
    
    def format_results_for_context(self, results: List[SearchResult]) -> str:
        """
        将搜索结果格式化为可用于AI上下文的文本
        
        Args:
            results: 搜索结果列表
            
        Returns:
            str: 格式化后的搜索上下文文本
        """
        if not results:
            return ""
        
        context = "## 搜索结果\n\n"
        
        for i, result in enumerate(results[:self.max_results], 1):
            context += f"### 结果 {i}\n"
            if result.title:
                context += f"**标题**: {result.title}\n"
            if result.url:
                context += f"**链接**: {result.url}\n"
            if result.snippet:
                # 限制每个结果的长度以控制token使用
                snippet = result.snippet[:200] + "..." if len(result.snippet) > 200 else result.snippet
                context += f"**内容**: {snippet}\n"
            context += "\n"
        
        # 检查token限制
        if len(context) > self.token_limit * 4:  # 粗略估算，1 token ≈ 4 字符
            context = context[:self.token_limit * 4] + "\n\n[搜索结果因长度限制被截断]"
        
        return context
    
    def should_trigger_search(self, query: str) -> bool:
        """
        判断查询是否应该触发搜索
        
        Args:
            query: 用户查询
            
        Returns:
            bool: 是否应该触发搜索
        """
        # 搜索触发关键词
        search_triggers = [
            '最新', '新闻', '现在', '目前', '当前', '今天', '今年', '2024', '2025',
            '实时', '更新', '发生', '发布', '公布', '宣布', '报告',
            '价格', '股价', '汇率', '天气', '疫情', '政策', '法规',
            '什么是', '如何', '怎么', '为什么', '哪里', '谁是',
            '公司', '企业', '集团', '机构', '组织', '品牌', '厂商',
            '科技', '技术', '产品', '服务', '业务', '行业'
        ]
        
        # 学术和技术查询
        academic_triggers = [
            '论文', '研究', '学术', '期刊', '会议', '技术', '算法', '方法',
            '工具', '软件', '框架', '库', '教程', '文档', '指南'
        ]
        
        query_lower = query.lower()
        
        # 检查是否包含搜索触发词
        for trigger in search_triggers + academic_triggers:
            if trigger in query_lower:
                return True
        
        # 检查是否包含疑问词
        question_words = ['什么', '如何', '怎么', '为什么', '哪里', '谁', '何时', '多少']
        for word in question_words:
            if word in query:
                return True
        
        return False

# 全局搜索服务实例
search_service = DuckDuckGoSearchService()